﻿#include "asm-generic/gpio.h"
#include "linux/delay.h"
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/timer.h>
#include <asm/uaccess.h>

struct gpio_desc{
	int gpio;
	int irq;
    char *name;
    int hmiture;
	struct timer_list hmiture_timer;
} ;

static struct gpio_desc gpios[1] = {
    {115, 0, "DTH11", },
};

/* 主设备号                                                                 */
static int major = 0;
static struct class *dht11_class;
static u64 g_dht11_irq_time[84];
static int g_dht11_irq_cnt = 0;



/* 环形缓冲区 */
#define BUF_LEN 128
static int g_hmitures[BUF_LEN];
static int r, w;

#define NEXT_POS(x) ((x+1) % BUF_LEN)

static int is_hmiture_buf_empty(void)
{
	return (r == w);
}

static int is_hmiture_buf_full(void)
{
	return (r == NEXT_POS(w));
}

static void put_hmiture(int hmiture)
{
	if (!is_hmiture_buf_full())
	{
		g_hmitures[w] = hmiture;
		w = NEXT_POS(w);
	}
}

static int get_hmiture(void)
{
	int hmiture = 0;
	if (!is_hmiture_buf_empty())
	{
		hmiture = g_hmitures[r];
		r = NEXT_POS(r);
	}
	return hmiture;
}


static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);


void parse_dht11_datas(void)
{
	int i;
	u64 time_lag;
	int bits = 0;
	char data = 0;
    char datas[5];
	int byte = 0;
	char crc;

    /* 数据个数: 可能是81、82、83、84 */
	if (g_dht11_irq_cnt < 81)
	{
		/* 出错 */
		put_hmiture(-1);
		put_hmiture(-1);

		// 唤醒APP
		wake_up_interruptible(&gpio_wait);
		g_dht11_irq_cnt = 0;
		return;
	}
    
	for(i = g_dht11_irq_cnt - 80; i < 84; i+=2)
	{
		data <<= 1;
		time_lag = g_dht11_irq_time[g_dht11_irq_cnt] - g_dht11_irq_time[g_dht11_irq_cnt - 1];

		if(time_lag > 50000)  //1
		{
			data |= 1;
		}
	
		bits++;
		if(bits == 8)
		{
			bits = 0;
            datas[byte] = data;
			byte++;
			data = 0;
		}
	}
    
	crc = datas[0] + datas[1] + datas[2] + datas[3];//check bit
	if(crc == datas[4])
	{
		//put in circle buffer
		put_hmiture(datas[0]);//integer
		put_hmiture(datas[2]);//integer
	}
	else
	{
		put_hmiture(-1);
		put_hmiture(-1);
	}

	wake_up_interruptible(&gpio_wait);
	g_dht11_irq_cnt = 0;
    
}

static void hmiture_timer_expire(unsigned long data)
{
	parse_dht11_datas();
}

static irqreturn_t dht11_isr(int irq, void *dev_id)
{
	struct gpio_desc* gpio_desc = dev_id;
	u64 time;

	//reveive interrupt,keep time
    time = ktime_get_ns();
	g_dht11_irq_time[g_dht11_irq_cnt] = time;
	g_dht11_irq_cnt++;

	//wake up interrupt
    if(g_dht11_irq_cnt == 84)   //??如果是81、82、83，又怎么解析数据呢，与解析数据的函数矛盾:设置定时器，定时器函数
	{
	   del_timer(&gpio_desc->hmiture_timer);
	   parse_dht11_datas();//parse data,put in circle buffer
	}

	return IRQ_HANDLED;
}

/* 实现对应的open/read/write等函数，填入file_operations结构体                   */
static ssize_t dht11_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	char ker_buf[2];

	if (size != 2)
		return -EINVAL;

	g_dht11_irq_cnt = 0;


	//start working : configure low level,last for 18ms
	gpio_request(gpios[0].gpio, gpios[0].name);
	gpio_direction_output(gpios[0].gpio, 0);
	gpio_free(gpios[0].gpio);
	mdelay(18);

    //configure input
	gpio_direction_input(gpios[0].gpio);//why no gpio_free??  no gpio_request so no gpio_free??NO!!!need request and free or pre_gpio_request not free

	gpios[0].irq  = gpio_to_irq(gpios[0].gpio);
	err = request_irq(gpios[0].irq, dht11_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, gpios[0].name, &gpios[0]);
    mod_timer(&gpios[0].hmiture_timer, jiffies + 10);	

	wait_event_interruptible(gpio_wait, !is_hmiture_buf_empty());
	free_irq(gpios[0].irq, &gpios[0]);

	/* 设置DHT11 GPIO引脚到初始状态 为下一次做准备 */
	err = gpio_request(gpios[0].gpio, gpios[0].name);
	gpio_direction_output(gpios[0].gpio, 1);
	gpio_free(gpios[0].gpio);


	ker_buf[0] = get_hmiture();
	ker_buf[1] = get_hmiture();
	if ((ker_buf[0] == (char)-1) && (ker_buf[1] == (char)-1))
	{
		printk("get err val\n");
		return -EIO;
	}
	err = copy_to_user(buf, &ker_buf, 2);
	
	return 2;
}


/* 定义自己的file_operations结构体                                              */
static struct file_operations dth11_drv_fops = {
	.owner	 = THIS_MODULE,
	.read    = dht11_drv_read,
};



static int __init dht11_drv_init(void)
{
    
	/* 设置DHT11 GPIO引脚的初始状态: output 1 */
    gpio_request(gpios[0].gpio, gpios[0].name);
	gpio_direction_output(gpios[0].gpio, 1);
	gpio_free(gpios[0].gpio);	

	setup_timer(&gpios[0].hmiture_timer, hmiture_timer_expire, (unsigned long)&gpios[0]);

	major = register_chrdev(0, "dht11", &dth11_drv_fops); 

	dht11_class = class_create(THIS_MODULE, "dht11_class");
	if (IS_ERR(dht11_class)) {
		unregister_chrdev(major, "dht11");
		return PTR_ERR(dht11_class);
	}

	device_create(dht11_class, NULL, MKDEV(major, 0), NULL, "dth11"); /* /dev/dth11 */
	
	return 0;
}


static void __exit dht11_drv_exit(void)
{
	device_destroy(dht11_class, MKDEV(major, 0));
	class_destroy(dht11_class);
	unregister_chrdev(major, "dht11");
}


/* 7. 其他完善：提供设备信息，自动创建设备节点  */

module_init(dht11_drv_init);
module_exit(dht11_drv_exit);

MODULE_LICENSE("GPL");


